/**
 * elancom Corporation copy right 2012 - 2015  
 *   
 * $Header: https://192.168.1.224/svn/elancom/product/elancom-platform/trunk/src/main/java/com/elancom/framework/commons/json/parser/deserializer/StackTraceElementDeserializer.java 1034 2012-07-02 03:09:12Z lanzhouxue $
 * $Id: StackTraceElementDeserializer.java 1034 2012-07-02 03:09:12Z lanzhouxue $
 * $Author: lanzhouxue $
 * $Date: 2012-07-02 11:09:12 +0800 (Mon, 02 Jul 2012) $
 * $Revision: 1034 $
 */
package com.elancom.framework.commons.json.parser.deserializer;

import java.lang.reflect.Type;

import com.elancom.framework.commons.json.JSONException;
import com.elancom.framework.commons.json.parser.DefaultJSONParser;
import com.elancom.framework.commons.json.parser.Feature;
import com.elancom.framework.commons.json.parser.JSONLexer;
import com.elancom.framework.commons.json.parser.JSONToken;

public class StackTraceElementDeserializer implements ObjectDeserializer {

	public final static StackTraceElementDeserializer instance = new StackTraceElementDeserializer();

	@Override
	@SuppressWarnings("unchecked")
	public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
		final JSONLexer lexer = parser.getLexer();
		if (lexer.token() == JSONToken.NULL) {
			lexer.nextToken();
			return null;
		}

		if (lexer.token() != JSONToken.LBRACE && lexer.token() != JSONToken.COMMA) {
			throw new JSONException("syntax error: " + JSONToken.name(lexer.token()));
		}

		String declaringClass = null;
		String methodName = null;
		String fileName = null;
		int lineNumber = 0;

		for (;;) {
			// lexer.scanSymbol
			final String key = lexer.scanSymbol(parser.getSymbolTable());

			if (key == null) {
				if (lexer.token() == JSONToken.RBRACE) {
					lexer.nextToken(JSONToken.COMMA);
					break;
				}
				if (lexer.token() == JSONToken.COMMA) {
					if (lexer.isEnabled(Feature.AllowArbitraryCommas)) {
						continue;
					}
				}
			}

			lexer.nextTokenWithColon(JSONToken.LITERAL_STRING);
			if (key == "className") {
				if (lexer.token() == JSONToken.NULL) {
					declaringClass = null;
				} else if (lexer.token() == JSONToken.LITERAL_STRING) {
					declaringClass = lexer.stringVal();
				} else {
					throw new JSONException("syntax error");
				}
			} else if (key == "methodName") {
				if (lexer.token() == JSONToken.NULL) {
					methodName = null;
				} else if (lexer.token() == JSONToken.LITERAL_STRING) {
					methodName = lexer.stringVal();
				} else {
					throw new JSONException("syntax error");
				}
			} else if (key == "fileName") {
				if (lexer.token() == JSONToken.NULL) {
					fileName = null;
				} else if (lexer.token() == JSONToken.LITERAL_STRING) {
					fileName = lexer.stringVal();
				} else {
					throw new JSONException("syntax error");
				}
			} else if (key == "lineNumber") {
				if (lexer.token() == JSONToken.NULL) {
					lineNumber = 0;
				} else if (lexer.token() == JSONToken.LITERAL_INT) {
					lineNumber = lexer.intValue();
				} else {
					throw new JSONException("syntax error");
				}
			} else if (key == "nativeMethod") {
				if (lexer.token() == JSONToken.NULL) {
					lexer.nextToken(JSONToken.COMMA);
				} else if (lexer.token() == JSONToken.TRUE) {
					lexer.nextToken(JSONToken.COMMA);
				} else if (lexer.token() == JSONToken.FALSE) {
					lexer.nextToken(JSONToken.COMMA);
				} else {
					throw new JSONException("syntax error");
				}
			} else if (key == "@type") {
				if (lexer.token() == JSONToken.NULL) {
					// skip
				} else if (lexer.token() == JSONToken.LITERAL_STRING) {
					final String elementType = lexer.stringVal();
					if (!elementType.equals("java.lang.StackTraceElement")) {
						throw new JSONException("syntax error : " + elementType);
					}
				} else {
					throw new JSONException("syntax error");
				}
			} else {
				throw new JSONException("syntax error : " + key);
			}

			if (lexer.token() == JSONToken.COMMA) {
				continue;
			}

			if (lexer.token() == JSONToken.RBRACE) {
				lexer.nextToken(JSONToken.COMMA);
				break;
			}

		}
		return (T) new StackTraceElement(declaringClass, methodName, fileName, lineNumber);
	}

	@Override
	public int getFastMatchToken() {
		return JSONToken.LBRACE;
	}
}
